
#define __CL_ENABLE_EXCEPTIONS
#define __NO_STD_VECTOR	// Use cl::vector and cl::string and 
#define __NO_STD_STRING // not STL versions, more on this later

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <utility>
#include <cl.hpp>

#ifdef _MSC_VER
#include <malloc.h>
#define alloca _alloca

#else//assume GCC

#endif 

#define DEF_TEST_PROGRAM		"test.cl"


class clTestBase{
public:	
	clTestBase()
	{
		clTestBase(DEF_TEST_PROGRAM, CL_DEVICE_TYPE_CPU);
	}

	clTestBase(std::string _filename,cl_device_type _cl_device)
		: filename(_filename), cl_device(_cl_device)
	{
		try{
	
			context=new cl::Context(cl_device, 0, NULL, NULL, NULL);
			devices=new cl::vector<cl::Device>();
			std::string progStr(loadProgram());
			source=new cl::Program::Sources (1, std::make_pair(progStr.c_str(),progStr.length()));
			program =new cl::Program(*context, *source);
			kernels=new cl::vector<cl::Kernel>();
		
			global_range=new cl::NDRange(256,256);
			local_range=new cl::NDRange();

		}catch (cl::Error err) {
		std::cerr
		<< "ERROR: "
		<< err.what()
		<< "("
		<< err.err()
		<< ")"
		<< std::endl;
		}
	}
	
	~clTestBase()
	{
		delete context;
		delete devices;
		delete source;
		delete program;
		delete kernels;
		delete global_range;
		delete local_range;
	}
	
	int run(std::string _kernel,cl::Buffer& buffer);
	cl::Context getContext(){
		return *context;
	}
private:
	cl_device_type				cl_device;
	std::string					filename;

	//OpenCL related members
	cl::Context* 				context;
	cl::vector<cl::Device>* 		devices;
	cl::Program::Sources* 		source;
	cl::Program* 				program;
	
	cl::NDRange*				global_range;
	cl::NDRange*				local_range;

	cl::vector<cl::Kernel>*		kernels;
	cl::vector<cl::Buffer>*		buffers;

	cl::CommandQueue*		queue;

	cl::vector<cl::KernelFunctor>* 	funcs;
	cl::vector<cl::Event>* 		events;

	std::string loadProgram();
};

